package com.aaa.sso.service;

import com.aaa.common.bo.LoginLog;
import com.aaa.common.bo.Member;
import com.aaa.common.bo.User;
import com.aaa.common.constants.ExceptionConstant;
import com.aaa.common.constants.LoginType;
import com.aaa.common.constants.ReturnStatus;
import com.aaa.common.util.CustomException;
import com.aaa.common.util.Result;
import com.aaa.sso.util.CustomUsernamePasswordToken;
import com.sun.media.jfxmedia.logging.Logger;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
 * @fileName:MemberAuthServiceImpl
 * @description:
 * @author:zhz
 * @createTime:2020/12/7 9:48
 * @version:1.0.0
 */
@Service("userAuthService")
public class UserAuthServiceImpl implements AuthService {


    /**
     * spring data提供的spring整合redis工具模板类，使用它直接操作redis
     */
    @Autowired
    private RedisTemplate redisTemplate;

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private HttpServletRequest request;

    @Autowired
    private RemoteUserService remoteUserService;



    @Autowired(required = false)
    public void setRedisTemplate(RedisTemplate redisTemplate) {
        RedisSerializer stringSerializer = new StringRedisSerializer();
        redisTemplate.setKeySerializer(stringSerializer);
        redisTemplate.setValueSerializer(stringSerializer);
        redisTemplate.setHashKeySerializer(stringSerializer);
        redisTemplate.setHashValueSerializer(stringSerializer);
        this.redisTemplate = redisTemplate;
    }

    @Override
    public Result authMemberOrUser(String userName, String passWord) {
        //验证用户密码是否为空，如果为空返回自定义错误
        if(StringUtils.isEmpty(userName)||StringUtils.isEmpty(passWord)){
            throw   new CustomException(
                    ExceptionConstant.INVALID_ARGUMENT.getErrorCode(),
                    ExceptionConstant.INVALID_ARGUMENT.getErrorMessage());
        }
        //获取Subject 主体对象
        Subject subject = SecurityUtils.getSubject();
        //判断当前用户是否认证过
        //if(!subject.isAuthenticated()) {
            //收集用户信息
            CustomUsernamePasswordToken usernamePasswordToken =
                    new CustomUsernamePasswordToken(userName, passWord, LoginType.USER.toString());
            try {
                //认证
                subject.login(usernamePasswordToken);
                // 记录登录日志
                insertLoginLog(userName,"0");
                //获取认证成功后的客户对象
                User user = (User) subject.getPrincipal();
                //删除redis中的唯一识别
                this.setRedisTemplate(redisTemplate);
                String userNameRedis="*"+userName+"*";
                Set<String> keys = stringRedisTemplate.keys(userNameRedis);
                for (String key : keys) {
                    System.out.println(key);
                }
                if(!CollectionUtils.isEmpty(keys)){
                    redisTemplate.delete(keys);
                    stringRedisTemplate.opsForValue().getOperations().delete(keys);
                    System.out.println("删除唯一识别");
                }
                //登录成功
                //1,生成token   (userName当前用户登录名称
                // System.currentTimeMillis()  midnight 00：00：00, January 1, 1970 UTC到当前时间的毫秒数)
                String accessToken = userName + System.currentTimeMillis();
                //该方法也可以用
                // String accessToken = UUID.randomUUID();
                //2,返回并保存到redis中
                Map resultMap = new HashMap<>();
                resultMap.put("accessToken",accessToken);
                //实际开发中  user表中的敏感信息，不可以直接返回给前端，即使返回也要经过加密处理
                resultMap.put("user",user);
                redisTemplate.opsForValue().set(accessToken, user.getUserName(),30, TimeUnit.MINUTES);
                return new Result(ReturnStatus.SUCCESS.getReturnCode(),
                        ReturnStatus.SUCCESS.getReturnMsg(), resultMap);
            } catch (AuthenticationException e) {
                e.printStackTrace();
            }
        //}
        insertLoginLog(userName,"1");
        return new Result(ReturnStatus.FAIL.getReturnCode(),
                ReturnStatus.FAIL.getReturnMsg(),"loginFail");
    }

    /**
     * 登出
     * @param token
     * @return
     */
    @Override
    public Result logout(String token) {
        Boolean delete = redisTemplate.delete(token);
        if(delete){
            new Result(ReturnStatus.SUCCESS.getReturnCode(),
                    ReturnStatus.SUCCESS.getReturnMsg(), delete);
        }
        return new Result(ReturnStatus.FAIL.getReturnCode(),
                ReturnStatus.FAIL.getReturnMsg(),delete);
    }

    /**
     * 登录日志记录方法
     * @param userName
     * @param status
     */
    private  void  insertLoginLog(String userName,String status){
        LoginLog loginLog = new LoginLog();
        loginLog.setBrowser("Chrome");
        loginLog.setLoginName(userName);
        loginLog.setLoginTime(new Date());
        loginLog.setIpaddr(request.getRemoteAddr());
        loginLog.setMsg("0".equals(status)?"登录成功":"登录失败");
        loginLog.setStatus(status);
        loginLog.setLoginLocation("内网IP");
        loginLog.setOs("Windows 10");
        remoteUserService.insert(loginLog);
    }
    @Override
    public boolean chechAccessToken(String accessToken) {
        return redisTemplate.hasKey(accessToken);
    }

    public void ss() {
        //删除redis中的唯一识别
//        Set keys = redisTemplate.keys("ljv" + "*");
        redisTemplate.opsForValue().set("ljv","11",30, TimeUnit.MINUTES);
        Object o = redisTemplate.opsForValue().get("ljv");
        System.out.println(o);
        boolean delete = redisTemplate.delete("ljv"+"*");
        System.out.println(delete);
    }

    public static void main(String[] args) {
        UserAuthServiceImpl userAuthService = new UserAuthServiceImpl();
        userAuthService.ss();
    }
}
